import 'package:flutter/material.dart';
import 'package:flutter_module/system/constant_config.dart';
import 'package:flutter_module/system/log_util.dart';
import 'package:flutter_module/util/event_bus.dart';
import 'package:flutter_module/viewModels/drawer_manager_viewmodel.dart';
import 'package:flutter_module/views/drawer_pages/base_page.dart';
import 'package:provider/provider.dart';

/// 抽屉展状态
enum DragStatus {
  ///全展开
  stateMaxExpanded,

  ///半展开
  stateHalfExpanded,

  ///最小展示
  stateMinExpanded,

  ///隐藏关闭
  stateClose,
}

///抽屉状态监听
typedef BottomDrawerStateListener = void Function(
    DragStatus status, double top);

/// 抽屉控件
class MapBottomDrawer extends StatefulWidget {
  const MapBottomDrawer({
    Key? key,
    this.top = 0,
    this.halfExpandedRate = 0.5,
    this.minExpandedRate = 0.1,
    this.isCanClose = true,
    this.dragStatus = DragStatus.stateClose,
    this.listener,
  }) : super(key: key);

  ///抽屉距离顶部距离
  final int top;

  ///半屏显示时的高度与本控件高度的比例（PS：不是屏幕比例）
  final double halfExpandedRate;

  ///最小显示高度与本控件高度的比例（PS：不是屏幕比例）
  final double minExpandedRate;

  ///初始化状态
  final DragStatus dragStatus;

  ///是否可关闭
  final bool isCanClose;

  ///抽屉回调接口
  final BottomDrawerStateListener? listener;

  @override
  _MapBottomDrawerState createState() => _MapBottomDrawerState();
}

class _MapBottomDrawerState extends State<MapBottomDrawer>
    with SingleTickerProviderStateMixin {
  ///可显示的最大高度 具体的像素
  double _maxChildSize = 0;

  ///屏幕高度，默认该控件是全屏显示的
  double _screenHeight = 0;

  ///当前抽屉所处状态
  late DragStatus _dragStatus;

  ///动画控制器
  late AnimationController _animalController;

  ///动画
  late Animation<double> _animation;

  ///动画执行时间
  final Duration _duration = const Duration(milliseconds: 250);

  ///listView 滚动控制
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    LogUtil.instance.printf("初始化 抽屉");

    ///创建动画控制器
    /// otherWidgets.duration 配置的是抽屉的自动打开与关闭滑动所用的时间
    _animalController = AnimationController(vsync: this, duration: _duration);
    switch (widget.dragStatus) {
      case DragStatus.stateMaxExpanded:
        _animalController.value = 1.0;
        break;
      case DragStatus.stateHalfExpanded:
        _animalController.value = widget.halfExpandedRate;
        break;
      case DragStatus.stateMinExpanded:
        _animalController.value = widget.minExpandedRate;
        break;
      case DragStatus.stateClose:
        _animalController.value = 0.0;
        break;
    }

    ///记录当前状态
    _dragStatus = widget.dragStatus;

    ///动画区间
    _animation = Tween(begin: 0.0, end: 1.0).animate(_animalController);
    EventBusUtils.getInstance().on<ChangeBottomDrawerStatus>().listen((event) {
      if (event.status != _dragStatus) {
        _changePosition(event.status);
      }
    });
  }

  ///初始化时，在initState()之后立刻调用
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    ///State 有一个属性是mounted 用来标识State当前是否正确绑定在View树中。
    ///当创建 State 对象，并在调用 State.initState 之前，
    ///framework 会根据 BuildContext 来标记 mounted，
    ///然后在 State的生命周期里面，这个 mounted 属性不会改变，
    ///直至 framework 调用 State.dispose
    if (mounted) {
      if (_maxChildSize == 0) {
        ///屏幕高度
        _screenHeight = ConstantConfig.screenSize.height;

        ///计算抽屉可展开的最大值
        _maxChildSize = _screenHeight - widget.top;
      }
    }
  }

  @override
  void dispose() {
    LogUtil.instance.printf("销毁抽屉");

    ///页面销毁时要销毁动画
    _animalController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    LogUtil.instance.printf("抽屉页面 build");
    return AnimatedBuilder(
      key: const ValueKey("drawer"),
      builder: (BuildContext context, Widget? child) {
        return Positioned(
          left: 0,

          ///由于父 控件是 Stack，这里面又用到Row，listview 之类的无限大小的控件，必须要给postioned一个明确的大小，要不会报错
          right: 0,

          ///这个明确的大小就是四个方向全要约束
          top: _screenHeight - _maxChildSize * _animalController.value,
          bottom: 0,
          child: child ?? _animationChild(),
        );
      },
      child: _animationChild(),
      animation: _animation,
    );
  }

  Widget _animationChild() {
    return GestureDetector(
      onVerticalDragUpdate: _move,
      onVerticalDragCancel: _cancel,
      onVerticalDragEnd: _end,
      onVerticalDragStart: _start,
      child: Column(
        children: [
          Container(
            padding:const EdgeInsets.all(8.0),
            decoration: const BoxDecoration(
                color: Colors.amberAccent,
                borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(10),
                    topRight: Radius.circular(10))),
            alignment: Alignment.center,
            width: double.infinity,
            child: const Text("我是头部拉手"),
          ),
          Expanded(
            child: Container(
              alignment: Alignment.topCenter,
              color: Colors.amberAccent,
              child: Selector<DrawerManagerViewModel, BasePage?>(
                selector: (context, model) => model.curPage,
                builder: (_, page, providerChild) {
                  LogUtil.instance.printf("抽屉页面更新", tag: "Provider Selector");
                  return AnimatedSwitcher(
                    duration: const Duration(milliseconds: 400),
                    transitionBuilder: (child, animation) {
                      final Animation<Offset> _offsetAnimation = Tween<Offset>(
                              begin: const Offset(1.0, 0.0),
                              end: const Offset(0.0, 0.0))
                          .animate(animation);
                      return SlideTransition(
                        child: child,
                        position: _offsetAnimation, //_offsetAnimation,
                      );
                    },
                    child: page == null
                        ? Container(key: const ValueKey("1"))
                        : page.getWidget(context, _scrollController),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }

  ///手势移动时，改变动画比例，重新计算抽屉容器大小
  void _move(DragUpdateDetails details) {
    ///如果抽屉在最高处，上下滑动优先处理listview的滑动
    if (_animalController.value == 1.0 &&
        ((details.delta.dy < 0 &&
                _scrollController.offset <=
                    _scrollController.position.maxScrollExtent) ||
            (details.delta.dy > 0 && _scrollController.offset > 0))) {
      _scrollController.jumpTo(_scrollController.offset - details.delta.dy);
    } else {
      ///计算移动距离和总高度的比例
      double delta = details.primaryDelta! / _maxChildSize;

      _animalController.value -= delta;

      EventBusUtils.getInstance().fire(ChangeBottomDrawerTop(
          _screenHeight - _maxChildSize * _animalController.value,
          _animalController.value));
    }
  }

  ///手势抬起
  void _end(DragEndDetails details) {
    var newStatus = _dragStatus;

    ///快速上滑,提升一档
    if (details.primaryVelocity! < -1000) {
      ///从最小状态到半屏状态
      if (_animalController.value < widget.halfExpandedRate) {
        newStatus = DragStatus.stateHalfExpanded;
      } else {
        ///从半屏状态到全屏状态
        newStatus = DragStatus.stateMaxExpanded;
      }
    } else if (details.primaryVelocity! > 1000) {
      ///快速下滑,降低一档
      ///listView 要回到第一条元素位置
      if (_scrollController.offset != 0.0) {
        _scrollController.animateTo(0.0,
            duration: const Duration(milliseconds: 400),
            curve: Curves.easeOutQuad);
      }

      ///从全屏到半屏状态
      if (_animalController.value > widget.halfExpandedRate) {
        newStatus = DragStatus.stateHalfExpanded;
      } else {
        ///如果设置可关闭，从最小状态，进入关闭状态 否则保持在最小状态
        if (widget.isCanClose &&
            _animalController.value <= widget.minExpandedRate) {
          newStatus = DragStatus.stateClose;
        } else {
          newStatus = DragStatus.stateMinExpanded;
        }
      }
    } else {
      ///比较离哪个位置最近
      var min = (1 - _animalController.value).abs();
      var v2 = (widget.halfExpandedRate - _animalController.value).abs();
      var v3 = (widget.minExpandedRate - _animalController.value).abs();
      var v4 = (0 - _animalController.value).abs();
      newStatus = DragStatus.stateMaxExpanded;
      if (min >= v2) {
        newStatus = DragStatus.stateHalfExpanded;
        min = v2;
      }
      if (min > v3) {
        newStatus = DragStatus.stateMinExpanded;
        min = v3;
      }

      if (min >= v4 && widget.isCanClose) {
        newStatus = DragStatus.stateClose;
      }
    }
    _changePosition(newStatus);
    if (newStatus != _dragStatus) {
      _dragStatus = newStatus;
      EventBusUtils.getInstance().fire(BottomDrawerStatusChange(_dragStatus));
    }
    EventBusUtils.getInstance().fire(ChangeBottomDrawerTop(
        _screenHeight - _maxChildSize * _animalController.value,
        _animalController.value));
  }

  ///根据状态滑动到相应的位置
  void _changePosition(DragStatus newStatus) {
    switch (newStatus) {
      case DragStatus.stateMaxExpanded:
        _animalController.forward().then((value) => EventBusUtils.getInstance()
            .fire(ChangeBottomDrawerTop(
                _screenHeight - _maxChildSize * _animalController.value,
                _animalController.value)));
        break;
      case DragStatus.stateHalfExpanded:
        _animalController
            .animateTo(widget.halfExpandedRate, duration: _duration)
            .then((value) => EventBusUtils.getInstance().fire(
                ChangeBottomDrawerTop(
                    _screenHeight - _maxChildSize * _animalController.value,
                    _animalController.value)));
        break;
      case DragStatus.stateMinExpanded:
        _animalController
            .animateTo(widget.minExpandedRate, duration: _duration)
            .then((value) => EventBusUtils.getInstance().fire(
                ChangeBottomDrawerTop(
                    _screenHeight - _maxChildSize * _animalController.value,
                    _animalController.value)));
        break;
      case DragStatus.stateClose:
        _animalController.reverse().then((value) => EventBusUtils.getInstance()
            .fire(ChangeBottomDrawerTop(
                _screenHeight - _maxChildSize * _animalController.value,
                _animalController.value)));
        Provider.of<DrawerManagerViewModel>(context, listen: false)
            .closeDrawer(isActive: false);
        break;
    }
    _dragStatus = newStatus;
    EventBusUtils.getInstance().fire(ChangeBottomDrawerTop(
        _screenHeight - _maxChildSize * _animalController.value,
        _animalController.value));
    EventBusUtils.getInstance().fire(BottomDrawerStatusChange(_dragStatus));
  }

  void _start(DragStartDetails details) {}

  void _cancel() {}
}
